using System;
using System.Diagnostics;
using System.Text;
using FluentNHibernate.Utils;
using NHibernate;
using Wikey.Domain.Components;
using Wikey.Extensibility.Interfaces;
using ISessionSource=Wikey.Domain.Components.ISessionSource;

namespace Wikey.Domain.Repository
{
    public interface IRepository {
        T Find<T>(int id);
        void Delete<T>(T target);
        void Save<T>(T target);
        ModelContext Context();
        void InfoSession();
    }


    public abstract class Repository : IRepository {
        private readonly ISession Session;
        private readonly ILogger logger = Factory.Get<ILogger>(); 

        protected Repository(ISessionSource source) : this(source.CreateSession()) { }
        protected Repository(ISession session) {
            Session = session;
            Session.FlushMode = FlushMode.Commit;
        }

        public T Find<T>(int id) {
            return Session.Get<T>(id);
        }

        public void Delete<T>(T target) {
            WithinTransaction(s => s.Delete(target));
        }
        public void Save<T>(T target) {
            WithinTransaction(s => s.SaveOrUpdate(target));
        }
        public void Save(params IEntity[] entities) {
            WithinTransaction(s => entities.Each(s.SaveOrUpdate));
        }
        public ModelContext Context() {
            FindStackTrace();
            logger.Debug(String.Format("Session is Open?{0}",Session.IsOpen));
            return new ModelContext(Session);
        }

        protected void WithinTransaction(Action<ISession> action) {
            var transaction = Session.BeginTransaction();
            try {
                action(Session);
                transaction.Commit();
            } catch (Exception ex ) {
                transaction.Rollback();
                logger.Error("Exception in Within Transaction", ex);
            } finally {
                transaction.Dispose();
            }
        }

        public void InfoSession()
        {
            if( Session == null || !Session.IsOpen)
            {
                logger.Debug("Session is somehow not open!");
            }
        }

        private void FindStackTrace()
        {
            var stack = new StackTrace();
            var builder = new StringBuilder();

            foreach (var frame in stack.GetFrames())
            {
                builder.Append(frame.GetMethod().Name).Append("|");
            }

            logger.Debug(builder.ToString());
        }
    }

    public interface  IEntity {}
}